home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / support / acttimes.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  9.9 KB  |  440 lines

  1. /* $Id: acttimes.c,v 1.3 1994/11/17 16:42:13 sob Exp sob $ */
  2.  
  3. /* This program will maintain the file active.times if your news software
  4. ** doesn't already do this for you.  The file contains a list of newsgroup
  5. ** names followed by the time of creation (in seconds since 1970) and the
  6. ** address of the creator.  Since we can't tell who actually created the
  7. ** group, they will all indicate acttimes@DOMAIN.
  8. **
  9. ** To use this without having NNTP around, undefine the NNTP_SUPPORT
  10. ** define, edit the other defines that follow to indicate your setup,
  11. ** and compile it with something like "cc -O -o acttimes acttimes.c".
  12. **
  13. ** Use either "acttimes -d" to start a daemon process that wakes up every
  14. ** 10 minutes (by default) to check if the active file is a different
  15. ** size, or put "acttimes" into your cron file to be run periodically.
  16. */
  17.  
  18. #define NNTP_SUPPORT        /* comment out if not using NNTP */
  19.  
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <signal.h>
  24. #include <errno.h>
  25. #ifdef NNTP_SUPPORT
  26. #include "../conf.h"
  27. #endif
  28. #ifdef USG
  29. #include <time.h>
  30. #else
  31. #include <sys/time.h>
  32. #endif
  33.  
  34. /* ---------- Start of configuration defines ---------- */
  35.  
  36. #ifdef USG
  37. #define TERMIO            /* Is this is termio system? */
  38. #endif
  39.  
  40. /* NNTP sites have the following already defined in ../conf.h */
  41.  
  42. #ifndef DOMAIN            /* our domain name */
  43. #define DOMAIN    "local"
  44. #endif
  45.  
  46. #ifndef ACTIVE_FILE        /* the active file for your news system */
  47. #define ACTIVE_FILE "/usr/lib/news/active"
  48. #endif
  49.  
  50. #ifndef ACTIVE_TIMES_FILE    /* the name of the file to update */
  51. #define ACTIVE_TIMES_FILE "/usr/lib/news/active.times"
  52. #endif
  53.  
  54. #ifndef SIGRET            /* set this to "int" if you have problems */
  55. #define SIGRET void
  56. #endif
  57.  
  58. #ifndef MAXPATHLEN        /* you'll probably want to leave this alone */
  59. #define    MAXPATHLEN    1024
  60. #endif
  61.  
  62. /*#define index   strchr    /* uncomment these if you need them */
  63. /*#define rindex  strrchr    /* (i.e. if index is undefined) */
  64.  
  65. /* ---------- End of configuration defines ---------- */
  66.  
  67. #ifdef TERMIO
  68. #include <termio.h>
  69. #else
  70. #include <sgtty.h>
  71. #endif
  72.  
  73. #define TIMER_FIRST 1
  74. #define TIMER_DEFAULT (10 * 60)
  75.  
  76. #define strnEQ(x,y,n) (!strncmp((x),(y),(n)))
  77.  
  78. extern errno;
  79.  
  80. char *index(), *rindex(), *malloc();
  81. SIGRET alarm_handler(), quit_handler();
  82. void active_times(), free_lines(), wrap_it_up();
  83.  
  84. typedef struct _active_line {
  85.     struct _active_line *link;
  86.     char *name;
  87.     char type;
  88. } ACTIVE_LINE;
  89.  
  90. ACTIVE_LINE *line_root = NULL, *last_line = NULL, *pline = NULL;
  91. long last_actsize;
  92. int daemon_delay = 0, kill_daemon = 0, old_groups = 0;
  93.  
  94. FILE *fp_lock;
  95.  
  96. struct stat filestat;
  97.  
  98. char buf[MAXPATHLEN];
  99. char lockfile[MAXPATHLEN];
  100.  
  101. main(argc, argv)
  102. int argc;
  103. char *argv[];
  104. {
  105.     int fd;
  106.     long pid;
  107.     char *cp;
  108.  
  109.     while (--argc) {
  110.     if (**++argv == '-') {
  111.         while (*++*argv) {
  112.         switch (**argv) {
  113.         case 'd':        /* run in daemon mode */
  114.             if (*++*argv <= '9' && **argv >= '0') {
  115.             daemon_delay = atoi(*argv) * 60;
  116.             while (*++*argv <= '9' && **argv >= '0') {
  117.                 ;
  118.             }
  119.             } else {
  120.             daemon_delay = TIMER_DEFAULT;
  121.             }
  122.             --*argv;
  123.             break;
  124.         case 'k':        /* kill running acttimes */
  125.             kill_daemon++;
  126.             break;
  127.         default:
  128.             fprintf(stderr, "Unknown option: '%c'\n", **argv);
  129.             exit(1);
  130.         }
  131.         }
  132.     } else {
  133.         fprintf(stderr,
  134.         "Usage:  acttimes [-d<mins>]\nOr:     acttimes -k\n");
  135.         exit(1);
  136.     }
  137.     }
  138.  
  139.     /* Set up a nice friendly umask. */
  140.     umask(002);
  141.  
  142.     /* Make sure we're not already running by creating a lock file. */
  143.     strcpy(lockfile, ACTIVE_TIMES_FILE);
  144.     if ((cp = rindex(lockfile, '/')) != 0) {
  145.     cp++;
  146.     } else {
  147.     cp = lockfile;
  148.     }
  149.     *cp = '\0';
  150.     sprintf(buf, "%sLOCK.%ld", lockfile, (long)getpid());
  151.     if ((fp_lock = fopen(buf, "w")) == 0) {
  152.     fprintf(stderr, "Unable to create lock temporary `%s'.\n", buf);
  153.     exit(1);
  154.     }
  155.     fprintf(fp_lock, "%ld\n", (long)getpid());
  156.     fclose(fp_lock);
  157.  
  158.     /* Try to link to lock file. */
  159.     strcat(lockfile, "LOCKacttimes");
  160.   dolink:
  161.     if (link(buf, lockfile) < 0) {
  162.       long otherpid;
  163.     /* Try to avoid possible race with daemon starting up. */
  164.     sleep (5);
  165.     if ((fp_lock = fopen(lockfile, "r")) == 0) {
  166.         fprintf(stderr, "unable to open %s\n", lockfile);
  167.         unlink(buf);
  168.         exit(1);
  169.     }
  170.     if (fscanf(fp_lock, "%ld", &otherpid) != 1) { 
  171.         fprintf(stderr, "unable to read pid from %s\n", lockfile);
  172.         unlink(buf);
  173.         fclose(fp_lock);
  174.         exit(1);
  175.     }
  176.     fclose(fp_lock);
  177.     if (kill(otherpid, kill_daemon ? SIGTERM : 0) == -1
  178.      && errno == ESRCH) {
  179.         if (unlink(lockfile) == -1) {
  180.         fprintf(stderr, "unable to unlink lockfile %s\n", lockfile);
  181.         unlink(buf);
  182.         exit(1);
  183.         }
  184.         if (!kill_daemon) {
  185.         goto dolink;
  186.         }
  187.     }
  188.     unlink(buf);
  189.     if (kill_daemon) {
  190.         fprintf(stderr, "killing currently running acttimes.\n");
  191.         exit(0);
  192.     } else {
  193.         fprintf(stderr, "acttimes is already running.\n");
  194.         exit(1);
  195.     }
  196.     }
  197.  
  198.     unlink(buf);            /* remove temporary LOCK.<pid> file */
  199.  
  200.     if (kill_daemon) {
  201.     fprintf(stderr, "acttimes is not running.\n");
  202.     wrap_it_up(1);
  203.     }
  204.  
  205. #ifdef SIGHUP
  206.     if( signal( SIGHUP, SIG_IGN ) != SIG_IGN ) {
  207.     signal( SIGHUP, quit_handler );
  208.     }
  209. #endif
  210.     if( signal( SIGINT, SIG_IGN ) != SIG_IGN ) {
  211.     signal( SIGINT, quit_handler );
  212.     }
  213. #ifdef SIGQUIT
  214.     if( signal( SIGQUIT, SIG_IGN ) != SIG_IGN ) {
  215.     signal( SIGQUIT, quit_handler );
  216.     }
  217. #endif
  218.     signal( SIGTERM, quit_handler );
  219. #ifdef SIGTTIN
  220.     signal( SIGTTIN, SIG_IGN );
  221.     signal( SIGTTOU, SIG_IGN );
  222. #endif
  223.     signal( SIGALRM, SIG_IGN );
  224.  
  225.     /* If we're not in daemon mode, run through once and quit. */
  226.     if (!daemon_delay) {
  227.     active_times();
  228.     } else {
  229.     /* For daemon mode, we cut ourself off from anything tty-related and
  230.     ** run in the background (involves forks, but no knives).
  231.     */
  232.     close(0);
  233.     if (open("/dev/null", 2) != 0) {
  234.         fprintf(stderr, "unable to open /dev/null!\n");
  235.         wrap_it_up(1);
  236.     }
  237.     close(1);
  238.     close(2);
  239.     dup(0);
  240.     dup(0);
  241.     while ((pid = fork()) < 0) {
  242.         sleep(2);
  243.     }
  244.     if (pid) {
  245.         exit(0);
  246.     }
  247. #ifdef TIOCNOTTY
  248.     if ((fd = open("/dev/tty", 1)) >= 0) {
  249.         ioctl(fd, TIOCNOTTY, (int*)0);
  250.         close(fd);
  251.     }
  252. #else
  253.     (void) setpgrp();
  254.     while ((pid = fork()) < 0) {
  255.         sleep(2);
  256.     }
  257.     if (pid) {
  258.         exit(0);
  259.     }
  260. #endif
  261.     /* Put our pid in the lock file for death detection */
  262.     if( (fp_lock = fopen(lockfile, "w")) != 0) {
  263.         fprintf(fp_lock, "%ld\n", (long)getpid());
  264.         fclose(fp_lock);
  265.     }
  266.  
  267.     signal(SIGALRM, alarm_handler);
  268.  
  269.     /* Start timer -- first interval is shorter than all others */
  270.     alarm(TIMER_FIRST);
  271.     for (;;) {
  272.         pause();        /* let alarm go off */
  273.         alarm(0);
  274.  
  275.         if (stat(ACTIVE_FILE, &filestat) < 0) {
  276.         fprintf(stderr, "Unable to stat active file -- quitting.\n");
  277.         wrap_it_up(1);
  278.         }
  279.         if (filestat.st_size != last_actsize) {
  280.         last_actsize = filestat.st_size;
  281.         active_times();
  282.         }
  283.         alarm(daemon_delay);
  284.     } /* for */
  285.     }/* if */
  286.  
  287.     wrap_it_up(0);
  288. }
  289.  
  290. SIGRET
  291. alarm_handler()
  292. {
  293.     signal(SIGALRM, alarm_handler);
  294. }
  295.  
  296. SIGRET
  297. quit_handler()
  298. {
  299.     wrap_it_up(0);
  300. }
  301.  
  302. void
  303. wrap_it_up(ret)
  304. {
  305.     unlink(lockfile);
  306.     exit(ret);
  307. }
  308.  
  309. void
  310. active_times()
  311. {
  312.     FILE *fp_active, *fp_date_r, *fp_date_w;
  313.     register char *cp;
  314.  
  315.     if ((fp_active = fopen(ACTIVE_FILE, "r")) == NULL) {
  316.     if (!daemon_delay) {
  317.         fprintf(stderr, "Unable to open active file.\n");
  318.     }
  319.     return;
  320.     }
  321.     if ((fp_date_r = fopen(ACTIVE_TIMES_FILE, "r")) == NULL) {
  322.     if (!daemon_delay) {
  323.         fprintf(stderr, "Creating active.times file.\n");
  324.     }
  325.     old_groups = 1;
  326.     } else {
  327.     old_groups = 0;
  328.     }
  329.     sprintf(buf, "%s.n", ACTIVE_TIMES_FILE);
  330.     if ((fp_date_w = fopen(buf, "w")) == NULL) {
  331.     if (!daemon_delay) {
  332.         fprintf(stderr, "Unable to create active.times file.\n");
  333.     }
  334.     return;
  335.     }
  336.  
  337.     /* Loop through entire active file and remember each line. */
  338.     while (fgets(buf, sizeof buf, fp_active)) {
  339.     if (!(cp = index(buf, ' ')) || cp[1] == '\0') {
  340.         continue;
  341.     }
  342.     cp[1] = '\0';        /* include trailing space */
  343.     if (!(cp = rindex(cp + 2, ' '))) {
  344.         continue;
  345.     }
  346.     pline = (ACTIVE_LINE*)malloc(sizeof (ACTIVE_LINE));
  347.     if (!pline) {
  348.         if (line_root) {
  349.         last_line->link = NULL;
  350.         free_lines();
  351.         }
  352.       bug_out:
  353.         fclose(fp_active);
  354.         fclose(fp_date_r);
  355.         fclose(fp_date_w);
  356.         return;
  357.     }
  358.     pline->name = malloc(strlen(buf) + 1);
  359.     if (!pline->name) {
  360.         if (line_root) {
  361.         last_line->link = NULL;
  362.         pline->name = NULL;
  363.         free_lines();
  364.         } else {
  365.         free(pline);
  366.         }
  367.         goto bug_out;
  368.     }
  369.     strcpy(pline->name, buf);
  370.     pline->type = cp[1];
  371.     if (!last_line) {
  372.         line_root = pline;
  373.     } else {
  374.         last_line->link = pline;
  375.     }
  376.     last_line = pline;
  377.     }
  378.     last_line->link = NULL;
  379.     fclose(fp_active);
  380.  
  381.     if (fp_date_r) {
  382.     /* Loop through date file, copying existing groups to new file. */
  383.     while (fgets(buf, sizeof buf, fp_date_r)) {
  384.         last_line = NULL;
  385.         for (pline = line_root; pline; pline = pline->link) {
  386.         if (strnEQ(buf, pline->name, strlen(pline->name))) {
  387.             fputs(buf, fp_date_w);
  388.             free(pline->name);
  389.             if (last_line) {
  390.             last_line->link = pline->link;
  391.             } else {
  392.             line_root = pline->link;
  393.             }
  394.             free(pline);
  395.             break;
  396.         }
  397.         last_line = pline;
  398.         }/* for */
  399.     }
  400.     }
  401.     /* Remaining entries from active file are new groups. */
  402.     for (pline = line_root; pline; pline = last_line) {
  403.     if (pline->type != 'x' && pline->type != '=') {
  404.         /* If it's not 'x'ed out, write it out with the current time. */
  405.         fprintf(fp_date_w, "%s%ld acttimes@%s\n", pline->name,
  406.         old_groups ? 30010440L : time(NULL), DOMAIN);
  407.     }
  408.     free(pline->name);
  409.     last_line = pline->link;
  410.     free(pline);
  411.     }
  412.     fclose(fp_date_w);
  413.     fclose(fp_date_r);
  414.     line_root = NULL;
  415.  
  416.     /* rm active.times.o */
  417.     sprintf(buf,"%s.o", ACTIVE_TIMES_FILE);
  418.     unlink(buf);
  419.     /* mv active.times active.times.o */
  420.     link(ACTIVE_TIMES_FILE, buf);
  421.     unlink(ACTIVE_TIMES_FILE);
  422.     /* mv active.times.n active.times */
  423.     sprintf(buf, "%s.n", ACTIVE_TIMES_FILE);
  424.     link(buf, ACTIVE_TIMES_FILE);
  425.     unlink(buf);
  426. }
  427.  
  428. void
  429. free_lines()
  430. {
  431.     for (pline = line_root; pline; pline = last_line) {
  432.     if (pline->name) {
  433.         free(pline->name);
  434.     }
  435.     last_line = pline->link;
  436.     free(pline);
  437.     }
  438.     line_root = NULL;
  439. }
  440.